package com.acme.bankapp.domain.accounts;

import com.acme.bankapp.domain.Client;
import com.acme.bankapp.exceptions.NegativeAmountException;
import com.acme.bankapp.exceptions.OverdraftLimitExceededException;

/**
 * 
 * Represents an account WITH overdraft.
 * 
 * Holds balance info.
 * Ensures safety of business rules.
 *
 */
public class CheckingAccount extends AbstractAccount {
	protected double overdraft;

	/**
	 * Creates a Checking account with zero balance and zero overdraft.
	 */
	public CheckingAccount() {
		balance = 0.;
		overdraft = 0.;
		accountType = AccountType.CHECKING;
		id = updateNextId();
	}

	/**
	 * Creates a Checking account with specified balance.
	 */
	public CheckingAccount(double balance, double overdraft) {
		this();
		this.balance = balance; 
		this.overdraft = overdraft; 
	}


	/**
	 * Withdraws amount from account, considering overdraft.
	 * {$inheritDoc}
	 * @param amount amount to be withdrawn.
	 * @return true if amount non-negative and amount is small enough to be withdrawn , false otherwise.
	 * @throws OverdraftLimitExceededException if appropriate :)
	 */
	public boolean withdraw(double amount) throws OverdraftLimitExceededException, NegativeAmountException {
		if (amount < 0.) {
			throw new NegativeAmountException();
		}

		if (balance - amount > -overdraft) {
			balance -= amount;
			return true;				  
		} else {
			throw new OverdraftLimitExceededException();
		}
	}

	/**
	 * Adds amount to account's balance.
	 * @param amount amount to be deposited.
	 * @return true if amount non-negative, false otherwise.
	 */
	public boolean deposit(double amount) throws NegativeAmountException {
		if (amount < 0.) {
			throw new NegativeAmountException();
		}
		balance += amount;
		return true;
	}

	public double getBalance() {
		return balance;
	}

	/**
	 * Returns balance as String.
	 */
	@Override
	public String toString() {
		return "" + getBalance();
	}

	@Override
	public long decimalValue() {
		return Math.round(getBalance());
	}	  

	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result
				+ ((accountType == null) ? 0 : accountType.hashCode());
		
		long temp;
		
		temp = Double.doubleToLongBits(balance);
		result = prime * result + (int) (temp ^ (temp >>> 32));

		temp = Double.doubleToLongBits(overdraft);
		result = prime * result + (int) (temp ^ (temp >>> 32));
		
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null) {
			return false;
		}
		if (getClass() != obj.getClass()) {
			return false;
		}
		CheckingAccount other = (CheckingAccount) obj;
		if (accountType != other.accountType) {
			return false;
		}
		if (Double.doubleToLongBits(balance) != Double 
				.doubleToLongBits(other.balance)) {
			return false;
		}
		if (Double.doubleToLongBits(overdraft) != Double
				.doubleToLongBits(other.overdraft)) {
			return false;
		}
		return true;
	}


	public double getOverdraft() {
		return overdraft;
	}

}
